﻿using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class Navigator : MonoBehaviour {
	//***************Debug*************
	public Material a;
	public Material b;
	//***************Debug*************
	public Node StartNode;
	public Node targetNode;
	public MapGenerator mapa;
	List<Node> PathToFollow = new List<Node> ();
	List<Node> OpenList = new List<Node>();
	List<Node> CloseList = new List<Node>();
	public GameObject light;
	void Start(){
		mapa = GameObject.FindGameObjectWithTag ("GameManager").GetComponent<MapGenerator> ();
	}
	public Node[] GetPathToDestiny(Node t){
		PathToFollow.Clear();
		OpenList.Clear ();
		CloseList.Clear ();
		CalculatePath (t);
		GenerateFinalPath ();
		PathToFollow.Reverse ();
		Node [] res = PathToFollow.ToArray ();
		return res;
	}
	//Por el momento funciona, no tocar, probablemente la cagues hahahaha.
	void CalculatePath(Node t){
		targetNode = t;
		StartNode = mapa.theMap.Tiles [(int)transform.position.x, (int)transform.position.z].GetComponentInChildren<Node> (); // aca flashea algo.
		Node ActualNode = StartNode;
		//Debug.Log ("StartNode " + ActualNode.Pos);
		ActualNode.CalculateNodeAtributes (targetNode);
		ActualNode.Parent = ActualNode;
		/*int iter = 0;*/
		while (ActualNode != targetNode /*&& iter < 10*/) {
			/*iter++;*/
			Node nodo;
			int minX = (int)ActualNode.Pos.x - 1;
			int maxX = (int)ActualNode.Pos.x + 2;
			int minY = (int)ActualNode.Pos.z - 1;
			int maxY = (int)ActualNode.Pos.z + 2;

			for (int i = minX; i<maxX; i++) {
				for (int j = minY; j < maxY; j++) {
					if(mapa.theMap.Tiles [i, j]){
						nodo = mapa.theMap.Tiles [i, j].GetComponentInChildren<Node> ();
						//***************Debug*************
						nodo.SetPathColor(a);
						//***************Debug*************
						if(NodeExistsInOL(nodo)&&nodo.Pos!=ActualNode.Pos){
							float dista = nodo.MovementCost;
							Node nodoParent = nodo.Parent;
							nodo.Parent = ActualNode;
							nodo.CalculateNodeAtributes(targetNode);
							if(dista < nodo.MovementCost){
								nodo.Parent = nodoParent;
								nodo.CalculateNodeAtributes(targetNode);
							}
						}else
						if(nodo.Walkable&&!NodeExistsInCL(nodo)&&nodo.Pos!=ActualNode.Pos){
							nodo.Parent = ActualNode;
							nodo.CalculateNodeAtributes(targetNode);
							OpenList.Add(nodo);
						}
					}
				}
			}
			OpenList.Remove(ActualNode);
			CloseList.Add(ActualNode);
			ActualNode = GetLowestFValueNode ();
			if(CloseList.IndexOf(ActualNode)!=-1)
				OpenList.Add (ActualNode);
		}
	}
	void GenerateFinalPath(){
		Node ActualNode = targetNode;
		do {
			ActualNode.SetPathColor(b);
			PathToFollow.Add (ActualNode);
			ActualNode = ActualNode.Parent;
		} while (ActualNode != StartNode);
	}
	//Retorna el Nodo de la OpenList con menor valor FValue.
	Node GetLowestFValueNode(){
		Node nodo = null;
		foreach (var item in OpenList) {
			if(nodo){
				if(item.FValue<nodo.FValue){
					nodo = item;
				}
			}else{
				nodo = item;
			}
		}
		return nodo;
	}
	bool NodeExistsInOL(Node n){
		foreach (var item in OpenList) {
			if(item.Pos.Equals(n.Pos))
				return true;
		}
		return false;
	}
	bool NodeExistsInCL(Node n){
		foreach (var item in CloseList) {
			if(item.Pos.Equals(n.Pos))
				return true;
		}
		return false;
	}
}
